home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 1 / Amiga Tools.iso / disk-tools / cd-tools / amicdrom / device.c < prev    next >
C/C++ Source or Header  |  1994-06-06  |  42KB  |  1,487 lines

  1. /* device.c:
  2.  *
  3.  * Handler for ISO-9660 (+ Rock Ridge) + HFS CDROM filing system.
  4.  * Based on DOSDEV V1.10 (2 Nov 87) by Matthew Dillon.
  5.  *
  6.  * ----------------------------------------------------------------------
  7.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  8.  * All rights reserved.
  9.  * This software may be freely distributed and redistributed for
  10.  * non-commercial purposes, provided this notice is included.
  11.  * ----------------------------------------------------------------------
  12.  * History:
  13.  *
  14.  * 20-Apr-94   fmu   Improved implementation of ACTION_INHIBIT.
  15.  * 17-Apr-94   fmu   Fixed bug concerning TRACKDISK disk change recognition.
  16.  * 12-Apr-94   fmu   Adapted ACTION_CURRENT_VOLUME to new filehandle
  17.  *             management.
  18.  * 09-Apr-94   fmu   Volume management: locks and filehandles will not
  19.  *                   be forgotten if a CDROM is removed from the drive.
  20.  * 06-Feb-94   dmb   - Full support for ACTION_INHIBIT
  21.  *                   - Change Check_Disk() for trackdisk support
  22.  * 05-Jan-93   fmu   - Retry displaying CD-DA icon if WB is not open.
  23.  *                   - id_UnitNumber of InfoData set to SCSI unit number.
  24.  *                   - Added Make_FSSM().
  25.  * 01-Jan-93   fmu   Support for symbolic links on RockRidge disks.
  26.  * 11-Dec-93   fmu   - ACTION_FLUSH always returns DOSTRUE.
  27.  *                   - ISO volume names are mapped to lowercase if
  28.  *                     the option LOWERCASE has been selected.
  29.  * 26-Nov-93   fmu   Some packets are now handled even if no disk
  30.  *                   is inserted.
  31.  * 21-Nov-93   fmu   - User programmable diskchange check interval.
  32.  *                   - Better support for ACTION_INHIBIT.
  33.  *                   - Handles filenames with ';'.
  34.  * 15-Nov-93   fmu   Missing return value for 'handler' inserted.
  35.  * 14-Nov-93   fmu   Added ACTION_USER packet for 'cdcontrol' program.
  36.  * 15-Oct-93   fmu   Adapted to new VOLUME structure.
  37.  * 10-Oct-93   fmu   - Creates volume node for 'no DOS' disks.
  38.  *             - Volume node now contains the correct volume
  39.  *               creation date.
  40.  * 09-Oct-93   fmu   - New format for mountlist startup field.
  41.  *             - SAS/C support.
  42.  *             - Debug process assembly tag adapted to small
  43.  *               memory model.
  44.  *             - Get_Startup moved to file devsupp.c.
  45.  * 03-Oct-93   fmu   - New buffering options 'S' and 'C'.
  46.  *                   - Fixed bug in cdlock.
  47.  *             - Fixed bug in ACTION_CURRENT_VOLUME.
  48.  * 27-Sep-93   fmu   Added ACTION_SAME_LOCK
  49.  * 25-Sep-93   fmu   - Send 'disk inserted' / 'disk removed' event via
  50.  *                     input.device if disk has been changed.
  51.  *                   - Corrected bug in ACTION_DISK_INFO.
  52.  * 24-Sep-93   fmu   - Added fast memory option 'F'.
  53.  *                   - Added ACTION_IS_FILESYSTEM.
  54.  *                   - Added 'write protected' error for write actions.
  55.  *                   - Added ACTION_CURRENT_VOLUME.
  56.  *                   - Unload handler code after ACTION_DIE.
  57.  *                   - Immediately terminate program if called from CLI.
  58.  *                   - Added library version number.
  59.  *                   - Set volume label to "Unnamed" for disks without name.
  60.  * 16-Sep-93   fmu   Added code to detect whether a lock stems from the
  61.  *                   current volume or from another volume which has
  62.  *                   been removed from the drive.
  63.  */
  64.  
  65. /*
  66.  *  Debugging routines are disabled by simply attempting to open the
  67.  *  file "debugoff", turned on again with "debugon".  No prefix may be
  68.  *  attached to these names (you must be CD'd to TEST:).
  69.  *
  70.  *  See Documentation for a detailed discussion.
  71.  */
  72.  
  73. #include <stdlib.h>
  74. #include <string.h>
  75.  
  76. #if defined(_DCC) && !defined(REGISTERED)
  77. #define abs
  78. #endif
  79.  
  80. #include "device.h"
  81. #include "intui.h"
  82. #include "devsupp.h"
  83. #include "cdcontrol.h"
  84. #include "params.h"
  85. #include "rock.h"
  86.  
  87. /*
  88.  *  Since this code might be called several times in a row without being
  89.  *  unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
  90.  *  for any global/static assignments that might be changed by running the
  91.  *  code.
  92.  */
  93.  
  94. PROC    *DosProc;     /* Our Process                        */
  95. DEVNODE *DosNode;     /* Our DOS node.. created by DOS for us            */
  96. DEVLIST *DevList;     /* Device List structure for our volume node       */
  97.  
  98. #if !defined(_DCC) || defined(REGISTERED)
  99. EXECLIB *SysBase;     /* EXEC library base                */
  100. #endif
  101. DOSLIB    *DOSBase;     /* DOS library base for debug process        */
  102. LIB    *UtilityBase; /* Utility library for miscellaneous tasks     */
  103.  
  104. CDROM   *g_cd;
  105. VOLUME  *g_volume;
  106. CDROM_OBJ *g_top_level_obj;
  107. char    *g_vol_name;
  108.  
  109. PORT *g_timer_mp;           /*  timer message port        */
  110. struct timerequest *g_timer_io; /*  timer i/o request        */
  111. ULONG g_timer_sigbit;
  112. ULONG g_dos_sigbit;
  113.  
  114. char    g_device[80];        /* SCSI device name */
  115. short    g_unit;            /* SCSI unit */
  116. short    g_use_rock_ridge;    /* Use Rock Ridge flag 'R' */
  117. short    g_map_to_lowercase;    /* Map to lower case flag 'L' */
  118. int     g_trackdisk;        /* Use trackdisk calls instead of SCSI-direct */
  119.  
  120. int    g_std_buffers;        /* Number of buffers for standard SCSI access */
  121. int    g_file_buffers;        /* Number of buffers for contiguous reads */
  122.  
  123. t_bool    g_show_version_numbers; /* Show version numbers */
  124.  
  125. int    g_scan_interval;    /* Time between successive diskchange checks */
  126.  
  127. t_bool    g_disk_inserted;    /* Is a disk inserted? */
  128.  
  129. char    g_play_cdda_command[80];/* Command invoked if appicon is activated */
  130.  
  131. int    g_inhibited;        /* Number of active INHIBIT(TRUE) packets */
  132.  
  133. struct MsgPort *DosTask;
  134.  
  135. #if !defined(NDEBUG) || defined(DEBUG_SECTORS)
  136.             /*    DEBUGGING            */
  137. PORT *Dbport;        /*    owned by the debug process    */
  138. PORT *Dback;        /*    owned by the DOS device driver    */
  139. short DBDisable;
  140. MSG DummyMsg;        /*    Dummy message that debug proc can use    */
  141. #endif
  142.  
  143. void *dosalloc(ulong);
  144. void dosfree (ulong *);
  145. void btos(LONG, char *);
  146. void *NextNode (NODE *);
  147. void *GetHead (LIST *);
  148. LOCK *cdlock(CDROM_OBJ *, int);
  149. void cdunlock (LOCK *);
  150. CDROM_OBJ *getlockfile (LONG);
  151. char *typetostr (int);
  152. void returnpacket(struct DosPacket *);
  153. int packetsqueued (void);
  154. int Check_For_Volume_Name_Prefix (char *);
  155. void Fill_FileInfoBlock (FIB *, CDROM_INFO *, VOLUME *);
  156. void Mount (void);
  157. void Unmount (int);
  158. int Mount_Check (void);
  159. void Check_Disk (void);
  160. void Send_Timer_Request (void);
  161. void Cleanup_Timer_Device (void);
  162. int Open_Timer_Device (void);
  163. void Send_Event (int);
  164. void Remove_Seglist (void);
  165. BPTR Make_FSSM (void);
  166.  
  167. /*
  168.  *  Don't call the entry point main().  This way, if you make a mistake
  169.  *  with the compile options you'll get a link error.
  170.  */
  171.  
  172. #if defined(LATTICE)
  173. int __saveds handler (void)
  174. #elif defined(_DCC) && !defined(REGISTERED)
  175. int _main (void)
  176. #elif defined(_DCC) && defined(REGISTERED)
  177. __geta4 int handler (void)
  178. #else
  179. int handler (void)
  180. #endif
  181. {
  182.     register PACKET *packet;
  183.     register short   error;
  184.     MSG     *msg;
  185.     ubyte   notdone = 1;
  186.     char    buf[256];
  187.     void    *tmp;
  188.     ULONG   signals;
  189.     ubyte   playing = FALSE;
  190.  
  191.     /*
  192.      *    Initialize all global variables. SysBase MUST be initialized before
  193.      *  we can make Exec calls. The DOS library is opened for the debug
  194.      *  process only.
  195.      */
  196.  
  197. #if !defined(_DCC) || defined(REGISTERED)
  198.     SysBase = *(EXECLIB **) 4L;
  199. #endif
  200.     DosProc = (PROC *) FindTask(NULL);
  201.     if (DosProc->pr_CLI)
  202.       return RETURN_FAIL;
  203.     DOSBase = (DOSLIB *) OpenLibrary ((UBYTE *) "dos.library",37);
  204.     UtilityBase = (LIB *) OpenLibrary ((UBYTE *) "utility.library",37);
  205.  
  206.     BUG2(DBDisable = 0;)                /*  Init. globals    */
  207.     BUG2(Dbport = Dback = NULL;)
  208.     DevList = NULL;
  209.     {
  210.     WaitPort(&DosProc->pr_MsgPort);     /*  Get Startup Packet    */
  211.     msg = GetMsg(&DosProc->pr_MsgPort);
  212.     packet = (PACKET *)msg->mn_Node.ln_Name;
  213.  
  214.     /*
  215.      *  Loading DosNode->dn_Task causes DOS *NOT* to startup a new
  216.      *  instance of the device driver for every reference.    E.G. if
  217.      *  you were writing a CON device you would want this field to
  218.      *  be NULL.
  219.      */
  220.  
  221.         DosNode = BTOC(packet->dp_Arg3);
  222.  
  223.     Init_Intui ();
  224.  
  225.     if (UtilityBase && DOSBase && Get_Startup (packet->dp_Arg2)) {
  226.         packet->dp_Res1 = DOS_TRUE;
  227.          packet->dp_Res2 = 0;
  228.  
  229.       /*
  230.        *  Set dn_Task field which tells DOS not to startup a new
  231.        *  process on every reference.
  232.        */
  233.  
  234.             DosNode->dn_Task = &DosProc->pr_MsgPort;
  235.         DosTask = DosNode->dn_Task;
  236.  
  237.       /*
  238.        *  Load dn_Startup field with a BPTR to a FileSysStartupMsg.
  239.        *  (According to the official documentation, this is not
  240.        *  required. Some debugging tools, however, depend on it.)
  241.        */
  242.         
  243.         DosNode->dn_Startup = Make_FSSM ();
  244.  
  245.     } else {                /*    couldn't open dos.library   */
  246.         packet->dp_Res1 = DOS_FALSE;
  247.         returnpacket(packet);
  248.         if (DOSBase) {
  249.           Close_Intui ();
  250.               if (UtilityBase)
  251.                 CloseLibrary (UtilityBase);
  252.           CloseLibrary ((struct Library *) DOSBase);
  253.         }
  254.         return 0;                /*    exit process            */
  255.     }
  256.     returnpacket(packet);
  257.     }
  258.  
  259.     g_inhibited = 0;
  260.  
  261.     g_disk_inserted = (Test_Unit_Ready (g_cd) ||
  262.                    Test_Unit_Ready (g_cd));
  263.  
  264.     /*
  265.      *    Initialize debugging code
  266.      */
  267.  
  268.     BUG2(dbinit();)
  269.  
  270.     BUG(dbprintf("%d std buffers, %d file buffers\n",
  271.              g_std_buffers, g_file_buffers);)
  272.  
  273.     g_timer_sigbit = 0;
  274.     if (g_scan_interval > 0) {
  275.       /* Initialize timer: */
  276.       if (Open_Timer_Device ())
  277.         Send_Timer_Request ();
  278.     }
  279.  
  280.     g_vol_name = dosalloc (128);
  281.  
  282.     /* Mount volume (if any disk is inserted): */
  283.     Mount ();
  284.  
  285.     g_dos_sigbit = 1L << DosProc->pr_MsgPort.mp_SigBit;
  286.  
  287.     /*
  288.      *    Here begins the endless loop, waiting for requests over our
  289.      *    message port and executing them.  Since requests are sent over
  290.      *    our message port, this precludes being able to call DOS functions
  291.      *    ourselves (that is why the debugging routines are a separate process)
  292.      */
  293.  
  294. top:
  295.     for (; notdone;) {
  296.     signals = Wait(g_dos_sigbit | g_timer_sigbit | g_app_sigbit);
  297.     if (signals & g_timer_sigbit) {
  298.       GetMsg (g_timer_mp);
  299.       if (!g_inhibited)
  300.         Check_Disk ();
  301.       Send_Timer_Request ();
  302.           if (g_retry_show_cdda_icon)
  303.         Show_CDDA_Icon ();
  304.     }
  305.     if (signals & g_app_sigbit) {
  306.       struct Message *msg;
  307.       while (msg = GetMsg (g_app_port)) {
  308.         ReplyMsg (msg);
  309.         if (g_play_cdda_command[0])
  310.           SystemTags ((UBYTE *) g_play_cdda_command,
  311.                   SYS_Input, Open ((UBYTE *) "NIL:", MODE_OLDFILE),
  312.                   SYS_Output, Open ((UBYTE *) "NIL:", MODE_NEWFILE),
  313.                   SYS_Asynch, TRUE,
  314.               TAG_END);
  315.         else {
  316.           int res;
  317.           if (playing)
  318.             res = Stop_Play_Audio (g_cd);
  319.           else
  320.             res = Start_Play_Audio (g_cd);
  321.               if (!res)
  322.             Display_Error ("Cannot perform play audio command!");
  323.           else
  324.             playing = !playing;
  325.         }
  326.       }
  327.     }
  328.     if (!(signals & g_dos_sigbit))
  329.       continue;
  330.     while (msg = GetMsg(&DosProc->pr_MsgPort)) {
  331.         packet = (PACKET *)msg->mn_Node.ln_Name;
  332.         packet->dp_Res1 = DOS_TRUE;
  333.         packet->dp_Res2 = 0;
  334.         error = 0;
  335. #ifndef NDEBUG
  336.         dbprintf("Packet: %3ld %08lx %08lx %08lx %10s ",
  337.         packet->dp_Type,
  338.         packet->dp_Arg1, packet->dp_Arg2,
  339.         packet->dp_Arg3,
  340.         typetostr(packet->dp_Type)
  341.         );
  342. #endif
  343.  
  344.             if (g_inhibited) {
  345.           switch (packet->dp_Type) {
  346.           /* packets we will handle even if the handler is inhibited: */
  347.           case ACTION_DIE:
  348.           case ACTION_INHIBIT:
  349.           case ACTION_MORE_CACHE:
  350.           case ACTION_DISK_INFO:
  351.             break;
  352.           /* packets we cannot handle because the handler is inhibited: */
  353.           default:
  354.             packet->dp_Res1 = DOS_FALSE;
  355.         packet->dp_Res2 = ERROR_NOT_A_DOS_DISK;
  356.             BUG(dbprintf("ERR=%ld\n", (long) packet->dp_Res2);)
  357.             returnpacket(packet);
  358.                 continue;            
  359.           }
  360.         } else if (DevList == NULL) {
  361.           switch (packet->dp_Type) {
  362.           /* packets we will handle even if no disk is inserted: */
  363.           case ACTION_DIE:
  364.           case ACTION_USER:
  365.           case ACTION_IS_FILESYSTEM:
  366.           case ACTION_INHIBIT:
  367.           case ACTION_MORE_CACHE:
  368.           case ACTION_FLUSH:
  369.         break;
  370.           /* packets we cannot handle because no disk is inserted: */
  371.           default:
  372.             packet->dp_Res1 = DOS_FALSE;
  373.             packet->dp_Res2 = (g_disk_inserted ? ERROR_NOT_A_DOS_DISK :
  374.                    ERROR_NO_DISK);
  375.             BUG(dbprintf("ERR=%ld\n", (long) packet->dp_Res2);)
  376.             returnpacket(packet);
  377.                 continue;            
  378.           }
  379.         }
  380.  
  381.         switch(packet->dp_Type) {
  382.         case ACTION_DIE:        /*    attempt to die?             */
  383.         notdone = 0;        /*    try to die                */
  384.         break;
  385.         case ACTION_USER:        /*  Mode,Par1,Par2            Bool    */
  386.             error = Handle_Control_Packet (packet->dp_Arg1,
  387.                            packet->dp_Arg2,
  388.                            packet->dp_Arg3);
  389.             break;
  390.         case ACTION_FINDINPUT:  /*  FileHandle,Lock,Name        Bool    */
  391.         {
  392.             if (Mount_Check ()) {
  393.               CDROM_OBJ *obj;
  394.               CDROM_OBJ *parentdir = getlockfile(packet->dp_Arg2);
  395.               int       offs;
  396.  
  397.               if (parentdir->volume != g_volume) {
  398.                   /* old lock from another disk: */
  399.             error = ERROR_DEVICE_NOT_MOUNTED;
  400.             goto openbreak;
  401.               }
  402.               
  403.               btos(packet->dp_Arg3,buf);
  404.               BUG(dbprintf("'%s' ", buf);)
  405.               offs = Check_For_Volume_Name_Prefix (buf);
  406.               if (obj = Open_Object (parentdir, buf + offs)) {
  407.                 if (obj->symlink_f) {
  408.                 error = ERROR_IS_SOFT_LINK;
  409.                 goto openbreak;
  410.             }
  411.             if (obj->directory_f) {
  412.                 error = ERROR_OBJECT_WRONG_TYPE;
  413.                 goto openbreak;
  414.             }
  415.               } else {
  416.             if (iso_errno == ISOERR_ILLEGAL_NAME) {
  417.                 error = ERROR_INVALID_COMPONENT_NAME;
  418.                 goto openbreak;
  419.             } else if (iso_errno == ISOERR_NOT_FOUND)
  420.                   error = ERROR_OBJECT_NOT_FOUND;
  421.             else if (iso_errno == ISOERR_NO_MEMORY) {
  422.               error = ERROR_NO_FREE_STORE;
  423.               goto openbreak;
  424.             } else if (iso_errno == ISOERR_IS_SYMLINK) {
  425.               error = ERROR_IS_SOFT_LINK;
  426.               goto openbreak;
  427.             } else {
  428.               error = 333;
  429.               goto openbreak;
  430.             }
  431.               }
  432.               if (!error) {
  433.                 g_volume->file_handles++;
  434.               ((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long) obj;
  435.             Register_File_Handle (obj);
  436.               }
  437.             } else
  438.               error = ERROR_NO_DISK;
  439.         }
  440.           openbreak:
  441.         break;
  442.         case ACTION_READ:        /*     FHArg1,CPTRBuffer,Length   ActLength  */
  443.         {
  444.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  445.             char      *ptr = (char *) packet->dp_Arg2;
  446.             long    length = packet->dp_Arg3;
  447.             int     actual;
  448.  
  449.             if (obj->volume != g_volume) {
  450.               /* old lock from another disk: */
  451.               error = ERROR_DEVICE_NOT_MOUNTED;
  452.               break;
  453.             }
  454.             actual = Read_From_File (obj, ptr, length);
  455.             packet->dp_Res1 = actual;
  456.         }
  457.         break;
  458.         case ACTION_END:        /*     FHArg1             Bool:TRUE  */
  459.         {
  460.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  461.  
  462.             if (obj->volume != g_volume) {
  463.               /* old lock from another disk: */
  464.               error = ERROR_DEVICE_NOT_MOUNTED;
  465.               break;
  466.             }
  467.             Unregister_File_Handle (obj);
  468.             Close_Object (obj);
  469.             g_volume->file_handles--;
  470.         }
  471.         break;
  472.         case ACTION_SEEK:        /*     FHArg1,Position,Mode        OldPosition*/
  473.             {
  474.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  475.             long offset = packet->dp_Arg2;
  476.             int mode = packet->dp_Arg3;
  477.             
  478.             if (obj->volume != g_volume) {
  479.               /* old lock from another disk: */
  480.               error = ERROR_DEVICE_NOT_MOUNTED;
  481.               break;
  482.             }
  483.             packet->dp_Res1 = obj->pos;
  484.             if (!Seek_Position (obj, offset, mode)) {
  485.               error = ERROR_SEEK_ERROR;
  486.               packet->dp_Res1 = -1;
  487.             }
  488.         }
  489.         break;
  490.         case ACTION_EXAMINE_NEXT: /*   Lock,Fib              Bool     */
  491.         {
  492.             FIB       *fib = BTOC (packet->dp_Arg2);
  493.             CDROM_OBJ *dir = getlockfile (packet->dp_Arg1);
  494.             CDROM_INFO info;
  495.  
  496.             if (dir->volume != g_volume) {
  497.               /* old lock from another disk: */
  498.               error = ERROR_DEVICE_NOT_MOUNTED;
  499.               break;
  500.             }
  501.             if (!dir->directory_f) {
  502.             error = ERROR_OBJECT_WRONG_TYPE;
  503.             break;
  504.             }
  505.             if (Examine_Next (dir, &info,
  506.                           (unsigned long *) &fib->fib_DiskKey)) {
  507.               error = 0;
  508.               Fill_FileInfoBlock (fib, &info, dir->volume);
  509.             } else {
  510.               error = ERROR_NO_MORE_ENTRIES;
  511.             }
  512.             break;
  513.         }
  514.         case ACTION_EXAMINE_OBJECT: /*   Lock,Fib            Bool       */
  515.         {
  516.             FIB *fib = BTOC (packet->dp_Arg2);
  517.                     CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  518.             CDROM_INFO info;
  519.  
  520.             if (obj->volume != g_volume) {
  521.               /* old lock from another disk: */
  522.               error = ERROR_DEVICE_NOT_MOUNTED;
  523.               break;
  524.             }
  525.             fib->fib_DiskKey = 0;
  526.             error = 0;
  527.             if (!CDROM_Info (obj, &info))
  528.               error = -1;
  529.             else
  530.               Fill_FileInfoBlock (fib, &info, obj->volume);
  531.         }
  532.         break;
  533.         case ACTION_INFO:        /*    Lock, InfoData      Bool:TRUE    */
  534.         tmp = BTOC(packet->dp_Arg2);
  535.         error = -1;
  536.         /*  fall through    */
  537.         case ACTION_DISK_INFO:  /*    InfoData      Bool:TRUE    */
  538.         {
  539.           if (Mount_Check ()) {
  540.             register INFODATA *id;
  541.  
  542.             (error) ? (id = tmp) : (id = BTOC (packet->dp_Arg1));
  543.             error = 0;
  544.             memset (id, 0, sizeof(*id));
  545.             id->id_UnitNumber = g_unit;
  546.             id->id_NumBlocksUsed = id->id_NumBlocks;
  547.             id->id_VolumeNode = (long) CTOB (DevList);
  548.             id->id_InUse = 0;
  549.                 id->id_DiskState = ID_WRITE_PROTECTED;
  550.             if (g_inhibited) {
  551.               id->id_DiskType = 0x42555359 /* "BUSY" */;
  552.               id->id_NumBlocks     = 0;
  553.               id->id_BytesPerBlock = 0;
  554.             } else {
  555.               id->id_DiskType = ID_DOS_DISK;
  556.               id->id_NumBlocks     = Volume_Size (g_volume);
  557.               id->id_BytesPerBlock = Block_Size (g_volume);
  558.             }
  559.           }
  560.         }
  561.         break;
  562.         case ACTION_IS_FILESYSTEM:   /*  -                      Bool */
  563.           packet->dp_Res1 = DOSTRUE;
  564.           break;
  565.         case ACTION_PARENT:     /*     Lock                ParentLock */
  566.             {
  567.           if (Mount_Check ()) {
  568.             if (packet->dp_Arg1) {
  569.               CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  570.               CDROM_OBJ *parent;
  571.           
  572.               if (obj->volume != g_volume) {
  573.                 /* old lock from another disk: */
  574.                 error = ERROR_DEVICE_NOT_MOUNTED;
  575.                 break;
  576.               }
  577.               if (Is_Top_Level_Object (obj)) {
  578.                 packet->dp_Res1 = packet->dp_Res2 = 0;
  579.               } else {
  580.                 parent = Find_Parent (obj);
  581.                 if (!parent) {
  582.                   if (iso_errno == ISOERR_NO_MEMORY)
  583.                     error = ERROR_NO_FREE_STORE;
  584.                   else
  585.                     error = ERROR_OBJECT_NOT_FOUND;
  586.                 } else {
  587.                   packet->dp_Res1 = (long)
  588.                 CTOB (cdlock (parent, ACCESS_READ));
  589.                 }
  590.               }
  591.             } else
  592.               error = ERROR_OBJECT_NOT_FOUND;
  593.           } else
  594.             error = ERROR_NO_DISK;
  595.         }
  596.         break;
  597.         case ACTION_LOCATE_OBJECT:    /*   Lock,Name,Mode        Lock       */
  598.         {
  599.           if (Mount_Check ()) {
  600.             CDROM_OBJ *parentdir = getlockfile (packet->dp_Arg1);
  601.                     CDROM_OBJ *obj;
  602.             int offs;
  603.  
  604.             if (parentdir->volume != g_volume) {
  605.               /* old lock from another disk: */
  606.               error = ERROR_DEVICE_NOT_MOUNTED;
  607.               break;
  608.             }
  609.             btos (packet->dp_Arg2, buf);
  610. #ifndef NDEBUG
  611.             dbprintf ("'%s' %ld ", buf, packet->dp_Arg3);
  612.             if (strcmp(buf,"debugoff") == 0)
  613.             DBDisable = 1;
  614.             if (strcmp(buf,"debugon") == 0)
  615.             DBDisable = 0;
  616. #endif
  617.  
  618.             offs = Check_For_Volume_Name_Prefix (buf);
  619.             if (buf[offs]==0) {
  620.               if (parentdir)
  621.                 obj = Clone_Object (parentdir);
  622.               else
  623.                 obj = Open_Top_Level_Directory (g_volume);
  624.             } else
  625.               obj = Open_Object (parentdir, buf + offs);
  626.             
  627.             if (obj) {
  628.               if (obj->symlink_f)
  629.                 error = ERROR_IS_SOFT_LINK;
  630.               else
  631.                 packet->dp_Res1 = (long) CTOB (cdlock (obj, packet->dp_Arg3));
  632.             } else {
  633.               if (iso_errno == ISOERR_SCSI_ERROR) {
  634.                 error = ERROR_OBJECT_NOT_FOUND;
  635.             Unmount (FALSE);
  636.               } else if (iso_errno == ISOERR_ILLEGAL_NAME)
  637.             error = ERROR_INVALID_COMPONENT_NAME;
  638.               else if (iso_errno == ISOERR_NOT_FOUND)
  639.             error = ERROR_OBJECT_NOT_FOUND;
  640.               else if (iso_errno == ISOERR_NO_MEMORY)
  641.                 error = ERROR_NO_FREE_STORE;
  642.               else if (iso_errno == ISOERR_IS_SYMLINK)
  643.                 error = ERROR_IS_SOFT_LINK;
  644.               else
  645.                 error = 333;
  646.             }
  647.           } else
  648.             error = ERROR_NO_DISK;
  649.         }
  650.         break;
  651.         case ACTION_COPY_DIR:   /*     Lock,                Lock       */
  652.             {
  653.           if (packet->dp_Arg1) {
  654.             CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  655.             CDROM_OBJ *new;
  656.             
  657.             if (obj->volume != g_volume) {
  658.               /* old lock from another disk: */
  659.               error = ERROR_DEVICE_NOT_MOUNTED;
  660.               break;
  661.             }
  662.             new = Clone_Object (obj);
  663.             if (!new)
  664.               error = ERROR_NO_FREE_STORE;
  665.             else
  666.               packet->dp_Res1 = (long) CTOB (cdlock (new, ACCESS_READ));
  667.           } else
  668.             packet->dp_Res1 = 0;
  669.         }
  670.         break;
  671.         case ACTION_FREE_LOCK:  /*     Lock,                Bool       */
  672.         if (packet->dp_Arg1);
  673.             cdunlock (BTOC(packet->dp_Arg1));
  674.         break;
  675.         case ACTION_CURRENT_VOLUME: /* FHArg1                   DevList    */
  676.             {
  677.           CDROM_OBJ *obj = (CDROM_OBJ*) packet->dp_Arg1;
  678.               if (obj)
  679.             packet->dp_Res1 = (long) CTOB (Find_Dev_List (obj));
  680.           else
  681.                 packet->dp_Res1 = (long) CTOB (DevList);
  682.               break;
  683.         }
  684.         case ACTION_INHIBIT:    /*     Bool                Bool       */
  685.                 if (packet->dp_Arg1 != DOS_FALSE) {
  686.                   /* true meens forbid access */
  687.           g_inhibited++;
  688.                   if (DevList)
  689.                     Unmount(FALSE);
  690.                   Hide_CDDA_Icon ();
  691.                   g_cd->t_changeint2 = -2;
  692.                 } else {
  693.                   /* false meens access allowed */
  694.           if (g_inhibited)
  695.             g_inhibited--;
  696.           if (g_inhibited == 0) {
  697.             g_disk_inserted = FALSE;
  698.                     Check_Disk();
  699.           }
  700.                 }
  701.         break;
  702.         /*
  703.          *  FINDINPUT and FINDOUTPUT normally should return the
  704.          *  'write protected' error. If the field 'Name', however,
  705.          *  designates the root (e.g. CD0:), then the 'wrong type'
  706.          *  error should be returned. Otherwise, AmigaDOS would do
  707.          *  some funny things (such as saying 'Volume CD0: is write-
  708.          *  protected') if you try to mount the handler with the
  709.          *  field 'Mount' set to 1.
  710.          */
  711.         case ACTION_FINDOUTPUT: /*   Handle  Lock  Name         Bool       */
  712.         case ACTION_FINDUPDATE: /*   Handle  Lock  Name         Bool       */
  713.         {
  714.           int pos;
  715.           
  716.           btos(packet->dp_Arg3,buf);
  717.           BUG(dbprintf("'%s' ", buf);)
  718.           if ((pos = Check_For_Volume_Name_Prefix (buf)) &&
  719.               buf[pos] == 0)
  720.         error = ERROR_OBJECT_WRONG_TYPE;
  721.           else
  722.         error = ERROR_DISK_WRITE_PROTECTED;
  723.           break;
  724.         }
  725.         case ACTION_SAME_LOCK: /*    Lock  Lock                 Bool       */
  726.         {
  727.           CDROM_OBJ *obj1 = getlockfile(packet->dp_Arg1),
  728.                     *obj2 = getlockfile(packet->dp_Arg2);
  729.  
  730.               if (Same_Objects (obj1, obj2))
  731.                 packet->dp_Res1 = DOSTRUE;
  732.           else
  733.                 packet->dp_Res1 = DOSFALSE;
  734.  
  735.           break;
  736.         }
  737.         case ACTION_READ_LINK: /*  Lock Name Buf Length         NumChar    */
  738.         {
  739.           CDROM_OBJ *obj;
  740.           CDROM_OBJ *parentdir = getlockfile (packet->dp_Arg1);
  741.           char *outbuf = (char *) packet->dp_Arg3;
  742.           t_ulong maxlength = packet->dp_Arg4;
  743.           int offs;
  744.           char buf[256];
  745.           int res;
  746.  
  747.           if (parentdir->volume != g_volume) {
  748.             /* old lock from another disk: */
  749.             error = ERROR_DEVICE_NOT_MOUNTED;
  750.             break;
  751.           }
  752.               BUG(dbprintf ("'%s' len=%lu ", packet->dp_Arg2, maxlength);)
  753.           offs = Check_For_Volume_Name_Prefix ((char *) packet->dp_Arg2);
  754.           obj = Open_Object (parentdir, (char *) packet->dp_Arg2 + offs);
  755.           if (obj) {
  756.             res = Get_Link_Name (obj, buf, sizeof (buf));
  757.         if (res == 0 ||
  758.             strlen (buf) + strlen (g_vol_name+1) + 1 >= maxlength)
  759.           strncpy (outbuf, "illegal_link", maxlength - 1);
  760.         else {
  761.           if (buf[0] == ':')
  762.             strcpy (outbuf, g_vol_name+1);
  763.           else
  764.             outbuf[0] = 0;
  765.           strcat (outbuf, buf);
  766.         }
  767.         outbuf[maxlength - 1] = 0;
  768.         Close_Object (obj);
  769.         packet->dp_Res1 = strlen (outbuf);
  770.           } else {
  771.         if (iso_errno == ISOERR_ILLEGAL_NAME)
  772.           error = ERROR_INVALID_COMPONENT_NAME;
  773.         else if (iso_errno == ISOERR_NOT_FOUND)
  774.           error = ERROR_OBJECT_NOT_FOUND;
  775.         else if (iso_errno == ISOERR_NO_MEMORY)
  776.           error = ERROR_NO_FREE_STORE;
  777.         else if (iso_errno == ISOERR_IS_SYMLINK)
  778.           error = ERROR_IS_SOFT_LINK;
  779.         else
  780.           error = 333;
  781.           }
  782.           break;
  783.         }
  784.         case ACTION_RENAME_DISK:
  785.         case ACTION_WRITE:
  786.         case ACTION_SET_PROTECT:
  787.         case ACTION_DELETE_OBJECT:
  788.         case ACTION_RENAME_OBJECT:
  789.         case ACTION_CREATE_DIR:
  790.         case ACTION_SET_COMMENT:
  791.         case ACTION_SET_DATE:
  792.         case ACTION_SET_FILE_SIZE:
  793.               error = ERROR_DISK_WRITE_PROTECTED;
  794.               break;
  795.         case ACTION_FLUSH:        /*     writeout bufs, disk motor off           */
  796.           break;
  797.         /*
  798.          *    A few other packet types which we do not support
  799.          */
  800.         case ACTION_MORE_CACHE: /*     #BufsToAdd            Bool       */
  801.         case ACTION_WAIT_CHAR:  /*     Timeout, ticks         Bool       */
  802.         case ACTION_SCREEN_MODE:/*     Bool(-1:RAW 0:CON)        OldState   */
  803.         default:
  804.         error = ERROR_ACTION_NOT_KNOWN;
  805.         break;
  806.         }
  807.         if (packet) {
  808.         if (error) {
  809.             BUG(dbprintf("ERR=%ld\n", error);)
  810.             packet->dp_Res1 = DOS_FALSE;
  811.             packet->dp_Res2 = error;
  812.         } else {
  813.             BUG(dbprintf("RES=%06lx\n", packet->dp_Res1));
  814.         }
  815.         returnpacket(packet);
  816.         }
  817.     }
  818.     }
  819.     BUG(dbprintf("Can we remove ourselves? ");)
  820.     Delay(100);        /*    I wanna even see the debug message! */
  821.     Forbid();
  822.     if (packetsqueued() ||
  823.         (g_volume && (g_volume->locks || g_volume->file_handles))) {
  824.     Permit();
  825.     BUG(dbprintf(" ..  not yet!\n");)
  826.     notdone = 1;
  827.     goto top;        /*  sorry... can't exit     */
  828.     } else
  829.     BUG(dbprintf(" ..  yes!\n");)
  830.  
  831.     /* remove timer device and any pending timer requests: */
  832.     if (g_timer_sigbit)
  833.       Cleanup_Timer_Device ();
  834.  
  835.     /* this is getting dangerous. We will unload our very own
  836.      * code via UnLoadSeg() and need to keep the system in
  837.      * Forbid() state in order to avoid getting the free memory
  838.      * reclaimed by other tasks. This means: *NO* Wait() after
  839.      * Unmount(TRUE) ist called!
  840.      */
  841.  
  842.     Unmount (TRUE);
  843.     
  844.     dosfree ((ulong *) g_vol_name);
  845.  
  846.     Cleanup_CDROM (g_cd);
  847.  
  848.     Close_Intui ();
  849.  
  850.     /*
  851.      *    Remove debug process, closedown, fall of the end of the world
  852.      *    (which is how you kill yourself if a PROCESS.  A TASK would have
  853.      *    had to RemTask(NULL) itself).
  854.      */
  855.  
  856.     BUG2(Delay (50);)
  857.     BUG2(dbuninit();)
  858.     if (UtilityBase)
  859.       CloseLibrary (UtilityBase);
  860.     if (DOSBase)
  861.       CloseLibrary ((struct Library *) DOSBase);
  862.     
  863.     return 0;
  864. }
  865.  
  866.  
  867. /*
  868.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  869.  *  can see by this and how the PACKET structure is extracted in the
  870.  *  GetMsg() of the main routine.
  871.  */
  872.  
  873. void returnpacket(struct DosPacket *packet)
  874. {
  875.     register struct Message *mess;
  876.     register struct MsgPort *replyport;
  877.  
  878.     replyport             = packet->dp_Port;
  879.     mess             = packet->dp_Link;
  880.     packet->dp_Port         = &DosProc->pr_MsgPort;
  881.     mess->mn_Node.ln_Name    = (char *)packet;
  882.     mess->mn_Node.ln_Succ    = NULL;
  883.     mess->mn_Node.ln_Pred    = NULL;
  884.     PutMsg(replyport, mess);
  885. }
  886.  
  887. /*
  888.  *  Are there any packets queued to our device?
  889.  */
  890.  
  891. int packetsqueued (void)
  892. {
  893.     return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
  894.         (void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
  895. }
  896.  
  897. /*
  898.  *  DOS MEMORY ROUTINES
  899.  *
  900.  *  DOS makes certain assumptions about LOCKS.    A lock must minimally be
  901.  *  a FileLock structure, with additional private information after the
  902.  *  FileLock structure.  The longword before the beginning of the structure
  903.  *  must contain the length of structure + 4.
  904.  *
  905.  *  NOTE!!!!! The workbench does not follow the rules and assumes it can
  906.  *  copy lock structures.  This means that if you want to be workbench
  907.  *  compatible, your lock structures must be EXACTLY sizeof(struct FileLock).
  908.  */
  909.  
  910. void *dosalloc(ulong bytes)
  911. {
  912.     register ulong *ptr;
  913.  
  914.     bytes += 4;
  915.     ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
  916.     *ptr = bytes;
  917.     return(ptr+1);
  918. }
  919.  
  920. void dosfree (ulong *ptr)
  921. {
  922.     --ptr;
  923.     FreeMem(ptr, *ptr);
  924. }
  925.  
  926. /*
  927.  *  Convert a BSTR into a normal string.. copying the string into buf.
  928.  *  I use normal strings for internal storage, and convert back and forth
  929.  *  when required.
  930.  */
  931.  
  932. void btos(LONG bstr, char *buf)
  933. {
  934.     unsigned char *str = BTOC(bstr);
  935.     bmov((char *) str+1, buf, *str);
  936.     buf[*str] = 0;
  937. }
  938.  
  939. /*
  940.  *  Some EXEC list handling routines not found in the EXEC library.
  941.  */
  942.  
  943. void *NextNode (NODE *node)
  944. {
  945.     node = node->mln_Succ;
  946.     if (node->mln_Succ == NULL)
  947.     return(NULL);
  948.     return(node);
  949. }
  950.  
  951. void *GetHead (LIST *list)
  952. {
  953.     if ((void *)list->mlh_Head != (void *)&list->mlh_Tail)
  954.     return(list->mlh_Head);
  955.     return(NULL);
  956. }
  957.  
  958. /*
  959.  *  The lock function.    The file has already been checked to see if it
  960.  *  is lockable given the mode.
  961.  */
  962.  
  963. LOCK *cdlock(CDROM_OBJ *cdfile, int mode)
  964. {
  965.   LOCK *lock = dosalloc (sizeof(LOCK));
  966.  
  967.   cdfile->volume->locks++;
  968.   lock->fl_Key = (long) cdfile;
  969.   lock->fl_Access = ACCESS_READ;
  970.   lock->fl_Task = &DosProc->pr_MsgPort;
  971.   lock->fl_Volume = (BPTR) CTOB (DevList);
  972.   Register_Lock (lock);
  973.   return(lock);
  974. }
  975.  
  976. void cdunlock (LOCK *lock)
  977. {
  978.   CDROM_OBJ *obj = (CDROM_OBJ *) lock->fl_Key;
  979.  
  980.   Unregister_Lock (lock);
  981.   --obj->volume->locks;
  982.   Close_Object (obj);
  983.   dosfree ((ulong *) lock);                /* free lock        */
  984. }
  985.  
  986. /*
  987.  *  GETLOCKFILE(bptrlock)
  988.  *
  989.  *  Return the CDROM_OBJ (file or directory) associated with the
  990.  *  given lock, which is passed as a BPTR.
  991.  *
  992.  *  According to the DOS spec, the only way a NULL lock will ever be
  993.  *  passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
  994.  *  In anycase, If a NULL lock is passed to me I simply assume it means
  995.  *  the root directory of the CDROM.
  996.  */
  997.  
  998. CDROM_OBJ *getlockfile (LONG lock)
  999. {
  1000.   LOCK *rl = BTOC (lock);
  1001.  
  1002.   if (rl)
  1003.     return (CDROM_OBJ *) rl->fl_Key;
  1004.   return g_top_level_obj;
  1005. }
  1006.  
  1007. /*
  1008.  * If p_pathname contains a ':' character, return the position of the first
  1009.  * character after ':'
  1010.  * Otherwise, return 0.
  1011.  */
  1012.  
  1013. int Check_For_Volume_Name_Prefix (char *p_pathname)
  1014. {
  1015.   char *pos = strchr (p_pathname, ':');
  1016.   
  1017.   return pos ? (pos - p_pathname) + 1 : 0;
  1018. }
  1019.  
  1020. /*
  1021.  * Fills a FileInfoBlock with the information contained in the
  1022.  * directory record of a CD-ROM directory or file.
  1023.  */
  1024.  
  1025. void Fill_FileInfoBlock (FIB *p_fib, CDROM_INFO *p_info, VOLUME *p_volume)
  1026. {
  1027.   char *src = p_info->name;
  1028.   char *dest = p_fib->fib_FileName+1;
  1029.   int len = p_info->name_length;
  1030.  
  1031.   if (p_info->symlink_f)
  1032.     p_fib->fib_DirEntryType = ST_SOFTLINK;
  1033.   else
  1034.     p_fib->fib_DirEntryType = p_info->directory_f ? ST_USERDIR : ST_FILE;
  1035.   
  1036.   /* I don't know exactly why I have to set fib_EntryType, but other
  1037.    * handlers (e.g. DiskHandler by J Toebes et.al.) also do this.
  1038.    */
  1039.    
  1040.   p_fib->fib_EntryType = p_fib->fib_DirEntryType;
  1041.   
  1042.   if (len == 1 && *src == ':') {
  1043.     /* root of file system: */
  1044.     p_fib->fib_DirEntryType = ST_USERDIR;
  1045.     /* file name == volume name: */
  1046.     memcpy (p_fib->fib_FileName, g_vol_name, (int)(g_vol_name[0])+1);
  1047.   } else {
  1048.     /* copy file name: */
  1049.     if (g_show_version_numbers) {
  1050.       p_fib->fib_FileName[0] = len;
  1051.       for (; len; len--)
  1052.         *dest++ = *src++;
  1053.     } else {
  1054.       short i, real_len=len;
  1055.       for (i=0; i<len; i++) {
  1056.         if (*src == ';')
  1057.       real_len = i;
  1058.         *dest++ = *src++;
  1059.       }
  1060.       p_fib->fib_FileName[0] = real_len;
  1061.     }
  1062.  
  1063.     if (g_map_to_lowercase && p_volume->protocol == PRO_ISO) {
  1064.       /* convert ISO filename to lowercase: */
  1065.       int i, len = p_fib->fib_FileName[0];
  1066.       char *cp = p_fib->fib_FileName + 1;
  1067.     
  1068.       for (i=0; i<len; i++, cp++)
  1069.         *cp = ToLower (*cp);
  1070.     }
  1071.   }
  1072.   p_fib->fib_Protection = 0;
  1073.   p_fib->fib_Size = p_info->file_length;
  1074.   p_fib->fib_NumBlocks = p_info->file_length >> 11;
  1075.   if (p_info->symlink_f)
  1076.     strcpy (p_fib->fib_Comment, "\x0DSymbolic link");
  1077.   else
  1078.     p_fib->fib_Comment[0] = 0;
  1079.  
  1080.   p_fib->fib_Date.ds_Days   = p_info->date / (24 * 60 * 60);
  1081.   p_fib->fib_Date.ds_Minute = (p_info->date % (24 * 60 * 60)) / 60;
  1082.   p_fib->fib_Date.ds_Tick   = (p_info->date % 60) * TICKS_PER_SECOND;
  1083. }
  1084.  
  1085. /*
  1086.  * Create Volume node and add to the device list. This will
  1087.  * cause the WORKBENCH to recognize us as a disk. If we don't
  1088.  * create a Volume node, Wb will not recognize us.
  1089.  */
  1090.  
  1091. void Create_Volume_Node (LONG p_disk_type, ULONG p_volume_date)
  1092. {
  1093.   DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  1094.   DEVLIST *dl;
  1095.   char *name;
  1096.  
  1097.   if (dl = Find_Volume_Node (g_vol_name + 1)) {
  1098.     BUG(dbprintf("[Reusing old volume node]");)
  1099.     Forbid ();
  1100.     DevList = dl;
  1101.     dl->dl_Task = &DosProc->pr_MsgPort;
  1102.     Permit ();
  1103.   } else {
  1104.     Forbid ();
  1105.     DevList = dl = dosalloc(sizeof(DEVLIST));
  1106.     dl->dl_Type = DLT_VOLUME;
  1107.     dl->dl_Task = &DosProc->pr_MsgPort;
  1108.     dl->dl_DiskType = p_disk_type;
  1109.     name = dosalloc (g_vol_name[0]+2);
  1110.     if (name) {
  1111.       dl->dl_Name = (BSTR) CTOB (name);
  1112.       memcpy (name, g_vol_name, g_vol_name[0]+2);
  1113.     }
  1114.     dl->dl_VolumeDate.ds_Days = p_volume_date / (24 * 60 * 60);
  1115.     dl->dl_VolumeDate.ds_Minute = (p_volume_date % (24 * 60 * 60)) / 60;
  1116.     dl->dl_VolumeDate.ds_Tick = (p_volume_date % 60) * TICKS_PER_SECOND;
  1117.     dl->dl_Next = di->di_DevInfo;
  1118.     di->di_DevInfo = (long)CTOB(dl);
  1119.     Permit ();
  1120.     Register_Volume_Node (dl);
  1121.   }
  1122. }
  1123.  
  1124. /*
  1125.  * Mount a volume.
  1126.  */
  1127.  
  1128. void Mount (void)
  1129. {
  1130.   char buf[33];
  1131.  
  1132.   if (Has_Audio_Tracks (g_cd))
  1133.     Show_CDDA_Icon ();
  1134.  
  1135.   g_volume = Open_Volume (g_cd, g_use_rock_ridge);
  1136.   if (!g_volume) {
  1137.     BUG(dbprintf ("!!! cannot open VOLUME (iso_errno=%d) !!!\n", iso_errno);)
  1138.     return;
  1139.   } else {
  1140.     g_disk_inserted = TRUE;
  1141.     g_cd->t_changeint2 = g_cd->t_changeint;
  1142.     g_top_level_obj = Open_Top_Level_Directory (g_volume);
  1143.     if (!g_top_level_obj) {
  1144.       BUG(dbprintf ("!!! cannot open top level directory !!!\n");)
  1145.       return;
  1146.     }
  1147.   }
  1148.   
  1149.   BUG(dbprintf ("***mounting*** ");)
  1150.  
  1151.   Volume_ID (g_volume, buf, sizeof (buf)-1);  
  1152.   g_vol_name[0] = strlen (buf);
  1153.   memcpy (g_vol_name+1, buf, strlen (buf));
  1154.  
  1155.   if (!(g_vol_name[0]))
  1156.     memcpy (g_vol_name, "\7Unnamed", 8);
  1157.  
  1158.   /* AmigaDOS expects the BCPL string g_vol_name to be null-terminated: */
  1159.   g_vol_name[(int)(g_vol_name[0])+1] = 0;
  1160.  
  1161.   /* convert ISO volume name to lowercase: */
  1162.   if (g_map_to_lowercase && g_volume->protocol == PRO_ISO) {
  1163.     int i;
  1164.     for (i=0; i<g_vol_name[0]; i++)
  1165.       g_vol_name[i+1] = ToLower (g_vol_name[i+1]);
  1166.   }
  1167.  
  1168.   g_volume->locks = Reinstall_Locks ();
  1169.   g_volume->file_handles = Reinstall_File_Handles ();
  1170.  
  1171.   Create_Volume_Node (ID_DOS_DISK, Volume_Creation_Date (g_volume));
  1172.   g_cd->t_changeint2 = g_cd->t_changeint;
  1173.   Send_Event (TRUE);
  1174. }
  1175.  
  1176. void Remove_Seglist (void)
  1177. {
  1178.   DOSINFO *di;
  1179.   void *dlp;
  1180.   DEVNODE *dn;
  1181.  
  1182.   di = BTOC (((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  1183.   dlp = &di->di_DevInfo;
  1184.   dn = BTOC (di->di_DevInfo);
  1185.  
  1186.   while (dn) {
  1187.     if (dn->dn_Task == DosTask) {
  1188.       BUG(dbprintf("got it!\n");)
  1189.       if (TypeOfMem (BADDR (dn->dn_SegList))) {
  1190.     UnLoadSeg (dn->dn_SegList);
  1191.     dn->dn_SegList = 0;
  1192.       } else
  1193.     BUG(dbprintf("not a valid seglist\n");)
  1194.  
  1195.       dn->dn_Task = NULL;
  1196.  
  1197.       *(BPTR *) dlp = dn->dn_Next;
  1198.       dosfree ((ulong *) dn);
  1199.  
  1200.       break;
  1201.     } else {
  1202.       dlp = &dn->dn_Next;
  1203.       dn = BTOC (dn->dn_Next);
  1204.     }
  1205.   }
  1206. }
  1207.  
  1208. /*  Remove a volume node from the DOS list.
  1209.  *  (Must be nested between Forbid() and Permit()!)
  1210.  *  Since DOS uses singly linked lists, we must (ugg) search it manually to find
  1211.  *  the link before our Volume entry.
  1212.  */
  1213.  
  1214. void Remove_Volume_Node (DEVLIST* p_volume)
  1215. {
  1216.   DOSINFO *di;
  1217.   DEVLIST *dl;
  1218.   void *dlp;
  1219.  
  1220.   Unregister_Volume_Node (p_volume);
  1221.  
  1222.   di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  1223.  
  1224.   dlp = &di->di_DevInfo;
  1225.   for (dl = BTOC(di->di_DevInfo); dl && dl != p_volume; dl = BTOC(dl->dl_Next))
  1226.     dlp = &dl->dl_Next;
  1227.   if (dl == p_volume) {
  1228.     *(BPTR *)dlp = dl->dl_Next;
  1229.     dosfree((ulong *) BTOC (dl->dl_Name));
  1230.     dosfree((ulong *) dl);
  1231.   } else {
  1232.     BUG(dbprintf("****PANIC: Unable to find volume node\n");)
  1233.   }
  1234. }
  1235.  
  1236. /*  Unmount a volume, and optionally unload the handler code.
  1237.  */
  1238.  
  1239. void Unmount (int p_remove_seglist)
  1240. {
  1241.   g_cd->t_changeint2 = g_cd->t_changeint;
  1242.   Hide_CDDA_Icon ();
  1243.  
  1244.   Forbid ();
  1245.  
  1246.   if (DevList) {
  1247.  
  1248.     BUG(dbprintf("***unmounting***");)
  1249.  
  1250.     Close_Object (g_top_level_obj);
  1251.     if (g_volume->locks == 0 && g_volume->file_handles == 0) {
  1252.       Remove_Volume_Node (DevList);
  1253.       Close_Volume (g_volume);
  1254.     } else {
  1255.       BUG(dbprintf("[there are still %d locks on this volume]",
  1256.                  g_volume->locks);)
  1257.       BUG(dbprintf("[there are still %d file handles on this volume]",
  1258.                  g_volume->file_handles);)
  1259.       DevList->dl_Task = NULL;
  1260.     }
  1261.  
  1262.     DevList = NULL;
  1263.   }
  1264.  
  1265.   Send_Event (FALSE);
  1266.  
  1267.   g_volume = 0;
  1268.  
  1269.   /* when the handler code exits the corresponding device
  1270.    * node (e.g. "CD0") will be modified. The handler code
  1271.    * will be unloaded and the task entry will be set to
  1272.    * zero, so the next device access will reload and
  1273.    * restart the handler code.
  1274.    */
  1275.  
  1276.   if (p_remove_seglist) {
  1277.     Remove_Seglist ();
  1278.   } else
  1279.     Permit ();
  1280. }
  1281.  
  1282. /*
  1283.  * Mount_Check returns 1 if a valid disk is inserted in the drive. A check is
  1284.  * only performed if previously the drive was empty.
  1285.  */
  1286.  
  1287. int Mount_Check (void)
  1288. {
  1289.   if (!g_disk_inserted) {
  1290.    /*
  1291.     * No disk was inserted up to now: we will check whether
  1292.     * a disk has been inserted by sending the test unit ready
  1293.     * command. We have to send the command twice because
  1294.     * the first SCSI command after inserting a new disk is
  1295.     * always rejected.
  1296.     */
  1297.     if (Test_Unit_Ready (g_cd) ||
  1298.         Test_Unit_Ready (g_cd)) {
  1299.       g_disk_inserted = TRUE;
  1300.       Mount ();
  1301.     } else {
  1302.       return 0;
  1303.     }
  1304.     if (DevList)
  1305.       return 1;
  1306.     else {
  1307.       /* Mount() did not succeed: */
  1308.       return 0;
  1309.     }
  1310.   }
  1311.   return 1;
  1312. }
  1313.  
  1314. /*
  1315.  *  Open timer device structures:
  1316.  */
  1317.  
  1318. int Open_Timer_Device (void)
  1319. {
  1320.   if (!(g_timer_mp = CreateMsgPort ())) {
  1321.     BUG(dbprintf ("cannot create timer message port!\n");)
  1322.     return 0;
  1323.   }
  1324.   if (!(g_timer_io = (struct timerequest *)
  1325.        CreateIORequest (g_timer_mp, sizeof (struct timerequest)))) {
  1326.     BUG(dbprintf ("cannot create timer i/o structure!\n");)
  1327.     DeleteMsgPort (g_timer_mp);
  1328.     return 0;
  1329.   }
  1330.   if (OpenDevice ((UBYTE *) TIMERNAME, UNIT_VBLANK,
  1331.             (struct IORequest *) g_timer_io, 0)) {
  1332.     BUG(dbprintf ("cannot open timer device!\n");)
  1333.     DeleteIORequest ((struct IORequest *) g_timer_io);
  1334.     DeleteMsgPort (g_timer_mp);
  1335.     return 0;
  1336.   }
  1337.   g_timer_sigbit = 1L << g_timer_mp->mp_SigBit;
  1338.   return 1;
  1339. }
  1340.  
  1341. /*
  1342.  *  Remove timer device structures:
  1343.  */
  1344.  
  1345. void Cleanup_Timer_Device (void)
  1346. {
  1347.   /* remove any pending requests: */
  1348.   if (!CheckIO ((struct IORequest *) g_timer_io))
  1349.     AbortIO ((struct IORequest *) g_timer_io);
  1350.   WaitIO ((struct IORequest *) g_timer_io);
  1351.   
  1352.   CloseDevice ((struct IORequest *) g_timer_io);
  1353.   DeleteIORequest ((struct IORequest *) g_timer_io);
  1354.   DeleteMsgPort (g_timer_mp);
  1355. }
  1356.  
  1357. /*
  1358.  *  Send timer request
  1359.  */
  1360.  
  1361. void Send_Timer_Request (void)
  1362. {
  1363.   g_timer_io->tr_node.io_Command = TR_ADDREQUEST;
  1364.   g_timer_io->tr_time.tv_secs = g_scan_interval;
  1365.   g_timer_io->tr_time.tv_micro = 0;
  1366.   SendIO ((struct IORequest *) g_timer_io);
  1367. }
  1368.  
  1369. /*
  1370.  *  Check whether the disk has been removed or inserted.
  1371.  */
  1372.  
  1373. void Check_Disk (void)
  1374. {
  1375.   int i;
  1376.   unsigned long l1, l2;
  1377.  
  1378.   BUG(dbprintf ("Checking Disk... ");)
  1379.   if (g_cd->use_trackdisk) {
  1380.     i = (Test_Unit_Ready (g_cd) ||
  1381.          Test_Unit_Ready (g_cd));
  1382.     l1 = g_cd->t_changeint;
  1383.     l2 = g_cd->t_changeint2;
  1384.     BUG(if (l1==l2 && i) dbprintf ("no disk change (T %ld)", l1);)
  1385.     if (l1!=l2 && i) {
  1386.       g_disk_inserted = TRUE;
  1387.       BUG(dbprintf ("disk has been inserted (T %ld)", l1);)
  1388.       if (DevList)
  1389.         Unmount (FALSE);
  1390.       Delay (50);
  1391.       Clear_Sector_Buffers (g_cd);
  1392.       Mount ();
  1393.     }
  1394.     BUG(if (l1==l2 && !i) dbprintf ("no disk in drive (T %ld)", l1);)
  1395.     if (l1!=l2 && !i) {
  1396.       g_disk_inserted = FALSE;
  1397.       BUG(dbprintf ("disk has been removed (T %ld)", l1);)
  1398.       if (DevList)
  1399.         Unmount (FALSE);
  1400.       g_cd->t_changeint2 = g_cd->t_changeint;
  1401.     }
  1402.   } else {
  1403.     if (g_disk_inserted) {
  1404.       if (Test_Unit_Ready (g_cd)) {
  1405.         BUG(dbprintf ("no disk change"));
  1406.       } else {
  1407.         g_disk_inserted = FALSE;
  1408.         BUG(dbprintf ("disk has been removed");)
  1409.         if (DevList)
  1410.           Unmount (FALSE);
  1411.         Hide_CDDA_Icon ();
  1412.       }
  1413.     }
  1414.     if (!g_disk_inserted) {
  1415.       if (Test_Unit_Ready (g_cd) ||
  1416.           Test_Unit_Ready (g_cd)) {
  1417.         g_disk_inserted = TRUE;
  1418.         BUG(dbprintf ("disk has been inserted");)
  1419.         Clear_Sector_Buffers (g_cd);
  1420.         Mount ();
  1421.       }
  1422.     }
  1423.   }
  1424.   BUG(dbprintf ("\n");)
  1425. }
  1426.  
  1427. /* The following lines will generate a `disk inserted/removed' event, in order
  1428.  * to get Workbench to rescan the DosList and update the list of
  1429.  * volume icons.
  1430.  */
  1431.  
  1432. void Send_Event (int p_inserted)
  1433. {
  1434.   struct IOStdReq *InputRequest;
  1435.   struct MsgPort *InputPort;
  1436.  
  1437.   if (InputPort = (struct MsgPort *) CreateMsgPort ()) {
  1438.     if (InputRequest = (struct IOStdReq *)
  1439.         CreateIORequest (InputPort, sizeof (struct IOStdReq))) {
  1440.       if (!OpenDevice ((UBYTE *) "input.device", 0,
  1441.                      (struct IORequest *) InputRequest, 0)) {
  1442.     static struct InputEvent InputEvent;
  1443.  
  1444.     memset (&InputEvent, 0, sizeof (struct InputEvent));
  1445.  
  1446.     InputEvent.ie_Class = p_inserted ? IECLASS_DISKINSERTED :
  1447.                        IECLASS_DISKREMOVED;
  1448.  
  1449.     InputRequest->io_Command = IND_WRITEEVENT;
  1450.     InputRequest->io_Data = &InputEvent;
  1451.     InputRequest->io_Length = sizeof (struct InputEvent);
  1452.  
  1453.     DoIO ((struct IORequest *) InputRequest);
  1454.  
  1455.     CloseDevice ((struct IORequest *) InputRequest);
  1456.       }
  1457.       DeleteIORequest (InputRequest);
  1458.     }
  1459.     DeleteMsgPort (InputPort);
  1460.   }
  1461. }
  1462.  
  1463. BPTR Make_FSSM (void)
  1464. {
  1465.   struct FileSysStartupMsg* fssm;
  1466.   struct DosEnvec *env;
  1467.   char *dev;
  1468.   
  1469.   fssm = dosalloc (sizeof (*fssm));
  1470.   fssm->fssm_Unit = g_unit;
  1471.   dev = dosalloc (strlen (g_device) + 2);
  1472.   strcpy (dev+1, g_device);
  1473.   dev[0] = strlen (g_device);
  1474.   fssm->fssm_Device = (BPTR) CTOB (dev);
  1475.   env = dosalloc (sizeof (struct DosEnvec));
  1476.   env->de_TableSize = 19;
  1477.   env->de_SizeBlock = 2048;
  1478.   env->de_Surfaces = 1;
  1479.   env->de_SectorPerBlock = 1;
  1480.   env->de_BlocksPerTrack = 1;
  1481.   env->de_DosType = 0x4E444F53; /* NDOS */
  1482.   fssm->fssm_Environ = (BPTR) CTOB (env);
  1483.   fssm->fssm_Flags = 0;
  1484.  
  1485.   return (BPTR) CTOB (fssm);
  1486. }
  1487.